#include "list.h"
#include "stack.h"
#include "queue.h"
#include "tree.h"
#include <stdio.h>
#include <assert.h>
#include "log.h"

#define assert_eq(a, b) assert((a) == (b))

static void list_test()
{
    List *list = list_new();
    int a[12] = {0};
    for (int i = 0; i < 12; i++)
    {
        a[i] = i;
        list_insert_tail(list, a + i);
        assert_eq(list_tail(list), a + i);
        assert_eq(list_len(list), i + 1);
    }

    for (int i = 0; i < list_len(list); i++)
    {
        assert_eq(list_find(list, &a[i]), i);
        assert_eq(list_get(list, i), &a[i]);
    }

    list_empty(list); 
    assert_eq(list->len, 0);
    assert_eq(list->head, NULL);
    list_free(list);
}

static void stack_test()
{
    Stack *stack = stack_new();
    int a = 5, b = 6, c = 7;
    stack_push(stack, &a);
    assert_eq(stack_top(stack), &a);
    stack_push(stack, &b);
    assert_eq(stack_top(stack), &b);
    stack_push(stack, &c);
    assert_eq(stack_depth(stack), 3);
    assert_eq(stack_top(stack), &c);
    assert_eq(stack_pop(stack), &c);
    assert_eq(stack_pop(stack), &b);
    assert_eq(stack_pop(stack), &a);
    assert_eq(stack_pop(stack), NULL);
    assert_eq(stack_pop(stack), NULL);
    assert_eq(stack_top(stack), NULL);
    assert_eq(stack_depth(stack), 0);
    stack_free(stack);
}

static void queue_test()
{
    Queue *q = queue_new();
    int a = 8, b = 9, c = 10;
    queue_in(q, &a);
    assert_eq(queue_tail(q), &a);
    queue_in(q, &b);
    assert_eq(queue_tail(q), &b);
    queue_in(q, &c);
    assert_eq(queue_tail(q), &c);
    assert_eq(queue_len(q), 3);
    assert_eq(queue_out(q), &a);
    assert_eq(queue_out(q), &b);
    assert_eq(queue_out(q), &c);
    assert_eq(queue_out(q), NULL);
    assert_eq(queue_out(q), NULL);
    queue_free(q);
}


// #[test]
extern void tree_test(void);
static void tree_test_wrap()
{
    tree_test();
}

extern void hashtable_test(void);
static void hashtable_test_wrap()
{
    hashtable_test();
}

struct Test{
    void (*test)();
    char *name;
};

struct Test TEST_TABLE[] = {
    {list_test, "list_test"},
    {stack_test, "stack_test"},
    {queue_test, "queue_test"},
    {tree_test_wrap, "tree_test"},
    {hashtable_test_wrap, "hashtable_test"}
};

#define array_size(a) (sizeof(a)/sizeof(a[0]))

int main(int argc, char *argv[])
{
    for (int i = 0; i < array_size(TEST_TABLE); i++)
    {
        println("running test%d %s...", i + 1, TEST_TABLE[i].name);
        TEST_TABLE[i].test();
        println("\033[32mpass\033[0m");
    }
    return 0;
}